package utils

import (
	"context"
	"googee/common/utils"
	"googee/service/leaderboard/model"

	"github.com/fatih/color"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
)

type boardDataRank struct {
	Rank int64 `db:"arank"`
}

type buckMinAndMaxScore struct {
	MaxScore int64 `db:"max_score"`
	MinScore int64 `db:"min_score"`
}

// 桶里面最大和最小的积分
func GetMinMaxScore(conn sqlx.SqlConn, ctx context.Context, bid int64, batchid int64) (int64, int64, error) {
	querysql := `SELECT max(score) as max_score, min(score) as min_score FROM leaderboards_data 
		WHERE bid=? and batchid=? limit 1`
	var x buckMinAndMaxScore

	err := conn.QueryRowCtx(ctx, &x, querysql, bid, batchid)
	if err != nil {
		return 0, 0, err
	}

	return x.MaxScore, x.MinScore, nil
}

func GetMaxBucket(conn sqlx.SqlConn, ctx context.Context, bid, batchid int64) (*model.LeaderboardsBuckets, error) {
	querysql := `SELECT  * FROM leaderboards_buckets 
		WHERE bid=? and batchid=? order by to_score desc limit 1`

	var b model.LeaderboardsBuckets
	err := conn.QueryRowCtx(ctx, &b, querysql, bid, batchid)
	if err != nil {
		return nil, err
	}

	return &b, nil
}

func RankForUser(conn sqlx.SqlConn, ctx context.Context, bid int64, userId int64, batchid int64, dense bool) (int64, error) {
	querysql := "SELECT * FROM leaderboards_data WHERE bid=? and user_id=? and batchid=? limit 1"

	var m model.LeaderboardsData

	var rank int64

	err := conn.QueryRowCtx(ctx, &m, querysql, bid, userId, batchid)
	if err != nil {
		return -1, err
	}

	if dense {
		querysql = "SELECT * FROM leaderboards_buckets WHERE bid=? AND from_score<=? AND ?<=to_score and batchid=? "

		var b model.LeaderboardsBuckets
		var from_dense, to_score int64 = 0, 0
		err = conn.QueryRowPartialCtx(ctx, &b, querysql, bid, m.Score, m.Score, batchid)
		if err != nil {
			max_bucket, err := GetMaxBucket(conn, ctx, bid, batchid)
			if err != nil {
				return -1, err
			}
			from_dense, to_score = max_bucket.FromDense, max_bucket.ToScore
		} else {
			from_dense, to_score = b.FromDense, b.ToScore
		}

		to_score = utils.MaxInt64(to_score, m.Score)
		color.Red("from_dense=%v", from_dense)
		color.Red("to_score=%v", to_score)
		querysql = `SELECT COUNT(user_id) AS rank FROM leaderboards_data 
			WHERE bid=? AND user_id<? AND ?<=score AND score<=? and batchid=? `

		var r boardDataRank
		err = conn.QueryRowCtx(ctx, &r, querysql, bid, userId, m.Score, to_score, batchid)
		if err != nil {
			return 0, err
		}

		rank = from_dense + r.Rank
	} else {
		querysql = "SELECT * FROM leaderboards_buckets WHERE bid=? AND from_score<=? AND ?<=to_score and batchid=? "

		var b model.LeaderboardsBuckets
		var from_rank, to_score int64 = 0, 0

		err = conn.QueryRowCtx(ctx, &b, querysql, bid, m.Score, m.Score, batchid)
		if err != nil {
			max_bucket, err := GetMaxBucket(conn, ctx, bid, batchid)
			if err != nil {
				return -1, err
			}
			from_rank, to_score = max_bucket.FromRank, max_bucket.ToScore
		} else {
			from_rank, to_score = b.FromRank, b.ToScore
		}

		to_score = utils.MaxInt64(to_score, m.Score)

		color.Red("from_rank=%v", from_rank)
		color.Red("to_score=%v", to_score)

		querysql = `SELECT COUNT(DISTINCT(score)) AS arank FROM leaderboards_data WHERE bid=? AND  ?<score AND score<=? and batchid=? `
		var r boardDataRank
		err = conn.QueryRowCtx(ctx, &r, querysql, bid, m.Score, to_score, batchid)
		if err != nil {
			return 0, err
		}
		rank = from_rank + r.Rank
	}

	return rank, nil
}
